#include <malloc.h>
#include <stdio.h>
#include <string.h>

#include "list.h"
#include "common.h"

int insert_cmd(struct server *, struct command *);
int insert_list(struct server *,struct command *);
void print_server(struct server *);
void print_cmd(struct command *);
void update_id(struct server *sv, int cmd_id, struct node *n);

int rcv_cmd(struct command *cmd){
	struct server *sv = NULL;
	sv = find_server(cmd->server_id);
	if(sv == NULL){
		new_server(cmd->server_id);
		sv=servers[server_count-1];
	}
	return insert_cmd(sv,cmd);
}

void send_cmd(struct server *sv, int start_id, int end_id, int flag){
	//printf("send cmd\n");
	struct node *p;
	p = sv->header;
	char buff[BUF_SIZE];
	if(flag == 0){
		p = p->next;
		while(p->cmd->cmd_id < start_id) 
			p=p->next;
		while(p->cmd->cmd_id >=start_id && p->cmd->cmd_id <= end_id){
			buff[0] =0x01;
			memcpy(buff+1,p->cmd,sizeof(struct command));
			flood(buff,sizeof(struct command)+1);
			p = p->next;
		}
	}
	else if(flag == 1){
		p = p->pre;
		while(p->cmd->cmd_id >=start_id && p->cmd->cmd_id <=end_id){
			buff[0] = 0x01;
			memcpy(buff+1,p->cmd,sizeof(struct command));
			flood(buff,sizeof(struct command)+1);
			p = p->pre;
		}
	}
}

void print_all_cmd(){
	int i;
	for(i=0; i<server_count; i++)
		print_server(servers[i]);
}

void print_server_cmd(int server_id){
	struct server * sv = NULL;
	sv = find_server(server_id);
	if(sv == NULL)
		printf("Server %d does not exist.\n",server_id);
	else 
		print_server(sv);
}

struct server * find_server(int server_id){
	int i;
	for(i=0;i<server_count;i++){
		if(servers[i]->server_id==server_id)
			return servers[i];
	}
	return NULL;
}

void new_server(int server_id){
	printf("new server: %d\n",server_id);
	struct server *sv = (struct server *)malloc(sizeof(struct server));
	struct node *header = (struct node*)malloc(sizeof(struct node));
  
	header->next = header->pre = header;
	header->cmd=(struct command *)malloc(sizeof(struct command));
	header->cmd->cmd_id = -1;

	sv->server_id = server_id;
	sv->length = 0;
	sv->min_seq_id = sv->max_seq_id = sv->max_rcv_id = -1;
	sv->header = header;

	servers[server_count] = sv;
	server_count++;
}

int insert_cmd(struct server *sv,struct command *cmd){
	int flag = 0;
	struct node *n = (struct node*)malloc(sizeof(struct node));
	n->cmd = (struct command*)malloc(sizeof(struct command));
	memcpy(n->cmd,cmd,sizeof(struct command));
	n->next = n->pre = NULL;

	struct node *p = sv->header;
	if(p == p->pre){
		p->next = p->pre = n;
		n->next = n->pre = p;
	} else{
		p = p->pre;
		while(p->cmd->cmd_id > cmd->cmd_id)
			p = p->pre;
		if(p->cmd->cmd_id == cmd->cmd_id){
			flag = 1;
			free(n->cmd);
			free(n);
		}	else {
			n->next = p->next;
			n->pre =p;
			n->pre->next = n;
			n->next->pre =n;
		}
	}
	if(flag ==0 ){
		sv->length++;
		update_id(sv, cmd->cmd_id, n);
	}
	return flag;
}

void update_id(struct server *sv, int cmd_id, struct node *n){
	//printf("before update: \n\tmin_seq_id:%d\t max_seq_id:%d\t max_rcv_id:%d\n",sv->min_seq_id, sv->max_seq_id, sv->max_rcv_id);
	//printf("insert id : %d\n",cmd_id);
	if(sv->length == 1)
		sv->min_seq_id = sv->max_seq_id = sv->max_rcv_id = cmd_id;
	else {
		if(cmd_id < sv->min_seq_id-1)
			sv->min_seq_id = sv->max_seq_id = cmd_id;
		else if(cmd_id == sv->min_seq_id-1)		
			sv->min_seq_id--;
		else if(cmd_id == sv->max_seq_id+1){
			while((n->next != sv->header) && (n->cmd->cmd_id == n->next->cmd->cmd_id-1))
			{
				//printf("update id n : %d\n",n->cmd->cmd_id);
				n = n->next;
			}
			if(n->next == sv->header){
				//printf("n->next == sv->header\n");
				sv->max_seq_id = n->cmd->cmd_id;
			}else {
				sv->max_seq_id = n->cmd->cmd_id;
				//printf("n->cmd->cmd_id != n->next->cmd->cmd_id-1\n");
			}
		}else if(cmd_id > sv->max_rcv_id)
			sv->max_rcv_id = cmd_id;
		if(sv->max_rcv_id < sv->max_seq_id)
			sv->max_rcv_id = sv->max_seq_id;
	}
	//printf("after update :\n\tmin_seq_id:%d\t max_seq_id:%d\t max_rcv_id:%d\n",sv->min_seq_id, sv->max_seq_id, sv->max_rcv_id);
	//print_server(sv);
}
		
void print_server(struct server *sv){
	printf("\n=============================================================\n");
	printf("server_id:%d\t number of command:%d\n",sv->server_id,sv->length);
	printf("min_seq_id:%d\t max_seq_id:%d\t max_rcv_id:%d\n",sv->min_seq_id, sv->max_seq_id, sv->max_rcv_id);
	struct node *p = sv->header->next;
	if(sv->length ==0) {
		printf("No command received from server %d.\n",sv->server_id);
		return ;
	}
	while(p!=sv->header){
		printf("cmd_id:%d command:%s\n",p->cmd->cmd_id,p->cmd->cmd);
		p = p->next;
	}
	printf("=============================================================\n");
}

void print_cmd(struct command *cmd){
	printf("cmd_type:%x\t,server_id:%d\t\n",cmd->cmd_type,cmd->server_id);
	printf("cmd_id:%d\t,cmd:%s\t\n",cmd->cmd_id,cmd->cmd);
}
